﻿#region [===== Using =====]
using System;
using System.Collections.Generic;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.Workflow;
#endregion

namespace TPG.SharePoint.Workflow
{
    /// <summary>
    /// A base page for workflow task forms.
    /// </summary>
    /// <remarks>
    /// This class implements the required framework code for handling workflow
    /// tasks. Global functions provided by this class are
    /// <list type="bullet">
    ///     <item>Retrieving and updating tasks data</item>
    ///     <item>Displaying a progress screen</item>
    ///     <item>Redirecting to the default view of the list</item>
    /// </list>
    /// As the implementer of workflow task forms you can
    /// derive your custom form from this class. By calling 
    /// <see cref="TaskPage.CommitTask" /> you can commit the 
    /// task and provide custom data for the workflow. The 
    /// <see cref="TaskPage.CancelTask" /> method redirects the 
    /// user back to the default view of the list. Task data can 
    /// be retrieved during updates of a workflow task using the 
    /// <see cref="TaskPage.GetWorkflowTaskData" /> method.
    /// </remarks>
    public abstract class TaskPage
        : ListWorkflowPage
    {
        #region [===== Fields =====]
        SPWorkflow _workflow;
        #endregion

        #region [===== Properties =====]
        /// <summary>
        /// Gets the workflow <see cref="PageType" />, indicating the type 
        /// of the workflow page.
        /// </summary>
        public override sealed PageType PageType
        {
            get { return PageType.Task; }
        }

        internal SPWorkflow Workflow
        {
            get
            {
                if (_workflow == null)
                {
                    Guid workflowId = new Guid(
                        (string)this.ListItem[
                            SPBuiltInFieldId.WorkflowInstanceID]);
                    _workflow = new SPWorkflow(this.Web, workflowId);
                }
                return _workflow;
            }
        }
        #endregion

        #region [===== Internal methods =====]
        internal override SPWorkflowAssociation GetWorkflowAssociation()
        {
            return this.Workflow.ParentAssociation;
        }

        internal override SPWorkflowTemplate GetWorkflowTemplate()
        {
            return this.WorkflowAssociationInternal.BaseTemplate;
        }
        #endregion

        #region [===== Protected methods =====]
        /// <summary>
        /// Commit the task using the specified data and redirect
        /// to the default view of the list with which the workflow
        /// is associated.
        /// </summary>
        /// <param name="data">Data used to update the task.</param>
        /// <exception cref="ArgumentNullException">Thrown when the 
        /// <paramref name="data"/> is not specified.</exception>
        protected void CommitTask(TaskData data)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }
            using (SPLongOperation operation = new SPLongOperation(this))
            {
                operation.LeadingHTML = GetProgressHtml();
                operation.Begin();
                SPListItem listItem = ListItem;
                if (data.ContentTypePropertiesChanged)
                {
                    foreach (KeyValuePair<Guid, object> propertyPair in
                        data.ContentTypeFieldValues)
                    {
                        listItem[propertyPair.Key] = propertyPair.Value;
                    }
                    listItem.Update();
                }
                if (data.ExtendedPropertiesChanged)
                {
                    SPWorkflowTask.AlterTask(
                        listItem, data.ExtendedProperties, true);
                }
                data.ResetStatus();
                operation.End(this.List.DefaultViewUrl,
                    SPRedirectFlags.UseSource, this.Context, null);
            }
        }

        /// <summary>
        /// Cancels the task by redirecting back to the default
        /// view of the list with which the workflow is associated.
        /// </summary>
        protected void CancelTask()
        {
            SPUtility.Redirect(this.List.DefaultViewUrl,
                SPRedirectFlags.UseSource, Context);
        }

        /// <summary>
        /// Gets the data for the task which is being edited as a
        /// <see cref="TaskData"/> object.
        /// </summary>
        /// <returns>The data for the task.</returns>
        protected TaskData GetWorkflowTaskData()
        {
            TaskData taskData = new TaskData(ListItem,
                SPWorkflowTask.GetExtendedPropertiesAsHashtable(ListItem));
            SPContentType taskContentType = ListItem.ContentType;
            SPContentTypeId wss3wfTaskContentTypeID =
                new SPContentTypeId(ContentTypeID.WorkflowTask);
            if (taskContentType.Id == wss3wfTaskContentTypeID ||
                taskContentType.Id.IsChildOf(wss3wfTaskContentTypeID))
            {
                taskData.AllowExtendedProperties = true;
            }
            return taskData;
        }

        /// <summary>
        /// Returns the progress html that is displayed for long running operations.
        /// </summary>
        /// <returns>The HTML to display with the progress image.</returns>
        protected virtual string GetProgressHtml()
        {
            return "Working..."; // TODO: use resources to load this data
        }
        #endregion
    }
}
